const puppeteer = require("puppeteer");
const config    = require('../config/config');
const utils      = require('../util/utils');
const fileUtil  = require('../util/file_util');
const fs        = require('fs');
const myRequest = require('request');
const searchUrl    = 'https://www.merchantwords.com/search/us/';

//黑名单网址
const blackList = [
    'https://www.merchantwords.com/products',
    'https://www.merchantwords.com/products-amazon-seo-service',
    'https://www.merchantwords.com/amazon-keyword-research-service',
    'https://www.merchantwords.com/keywordadvisor-information',
    'https://www.merchantwords.com/products#signUp'
];


class merchant_v1{
    constructor(options) {
        if(!merchant_v1.single){
            this.windowOptions = [
                '--disable-web-security',
                `--disable-extensions-except=${options.wyfyPluginPath},${options.googlePluginPath},${options.proxyPath}`,
                `--load-extension=${options.wyfyPluginPath},${options.googlePluginPath},${options.proxyPath}`,
                // `--proxy-server=http://${config.PROXY.HOST}:${config.PROXY.PORT}`,
                `–default-browser-check` //不检查默认浏览器
            ];
            this.browser = null;
            this.page = null;
            this.timeOptions = { waitUntil: ["domcontentloaded"] };
            this.targetUrl = options.targetUrl;
            this.options = options;
            this.monitorTimers = [];
            this.searchTime = null;
            this.closeFn = options.closeFn;
            this.productObj = options.productObj;
            this.bookmarkPath = options.bookmarkPath;
            this.token = options.token;
            merchant_v1.single = this;
        }
        return merchant_v1.single;
    }

    async loadWindow(){
        if(this.browser){
            await this.browser.newPage();
            return;
        }
        this.browser = await puppeteer.launch({
            headless: false,
            ignoreHTTPSErrors: true,
            // credentialsEnableService:false,
            // passwordManagerEnabled:false,
            ignoreDefaultArgs: ['--enable-automation','--disable-extensions'],
            defaultViewport: {
                width: 0,
                height: 0
            },
            args: this.windowOptions,
            // userDataDir: this.bookmarkPath,
        });

        this.page = await this.browser.newPage();
        console.log(`上下文初始完毕`);
        //关闭起始页的page
        await this.closeFirstPage();

        //开启拦截器
        await this.openPageInterception(this.page);
        await this.camouflageBrowser();
        //事件监听
        await this.intercept();

        await this.goPage(this.targetUrl);
        console.log(`打开页面成功`);
        //页面加载完毕后的后置操作
        await this.after();
    }

    async openPageInterception(page){
        page.setRequestInterception(true);
    }

    async closeFirstPage(){
        let pages = await this.browser.pages();
        if(!pages || pages.length === 0){
            return;
        }
        await pages[0].close();
    }

    async monitorTimer(){
        //监听新页面
        let newPageTimer = setInterval(async () => {
            try {
                let pageCache = await this.browser.pages();
                if(!pageCache || pageCache.length === 0){
                    return;
                }
                for (let i=0;i<pageCache.length;i++){
                    let otherPage = pageCache[i];
                    let url = otherPage.url()
                    if(url.indexOf(this.targetUrl) !== -1 || url.indexOf('chrome://settings') !== -1){
                        if(otherPage != this.page){
                            //如果打开了多个魔词界面 强制关闭
                            // console.log(`close a page..  ${pageCache[i].url()}`)
                            // await otherPage.close();
                        }
                    }
                    if(blackList.indexOf(url) !== -1){
                        await otherPage.close();
                    }

                }
                pageCache = await this.browser.pages();
                if(pageCache.length === 0){
                    await this.closeWindows();
                }
            } catch (e) {

            }
        },500);
        this.monitorTimers.push(newPageTimer);
    }

    async after(){
        //新page监听
        await this.monitorTimer();
        //注入js
        await this.injectScript();
    }

    async injectScript(){
        //禁用敏感组件
        await this.disableAssembly()
    }

    async disableAssembly(){
        //监听界面数据 禁用账户栏
        let monitorAccountTimer = setInterval(async () => {
            try {
                let accountElements = await this.page.$$(".header__content-bar > .nav > li");
                if(accountElements && accountElements.length !== 0){
                    for (let i=0;i<accountElements.length;i++) {
                        if(i === 4){
                            continue;
                        }
                        let el = accountElements[i];
                        await this.page.evaluate((el, value) => {
                                el.setAttribute('style', value)
                            },
                            el,
                            'display:none'
                        );
                    }
                }
            }catch (e) {
            }
        },500);

        //禁用聊天框
        let timer4 = setInterval(async () => {
            try {
                let IMDom = await this.page.$("#launcher");
                if(IMDom){
                    await this.page.evaluate((el, value) => {
                            el.setAttribute('style', value)
                        },
                        IMDom,
                        'display:none'
                    );
                }
            } catch (e) {
            }
        },500);
        //填充账号密码
        let fillAccountTimer = setInterval(async () => {

            try{
                let emailSelector = '#field-email-3\\#';
                let pwdSelector = '#field-pass-3\\#';
                let formSelector = '#loginForm';

                let accountDom = await this.page.$(emailSelector);
                let passwordDom = await this.page.$(pwdSelector);
                let formDom = await this.page.$(formSelector);

                if(formDom){
                    //隐藏输入框
                    await this.page.evaluate((el, value) => {
                            el.setAttribute('style', value);
                        },
                        accountDom,
                        'display:none'
                    );

                    await this.page.evaluate((el, value) => {
                            el.setAttribute('style', value);
                        },
                        passwordDom,
                        'display:none'
                    );

                    let oldEmail = await this.page.$eval(emailSelector,input => input.value);
                    let oldPassword = await this.page.$eval(pwdSelector,input => input.value);

                    if(!oldEmail){
                        await this.page.evaluate((el, value) => {
                                el.setAttribute('value', value)
                            },
                            accountDom,
                            this.userName
                        );
                    }
                    if(!oldPassword){
                        await this.page.evaluate((el, value) => {
                                el.setAttribute('value', value);
                            },
                            passwordDom,
                            this.password
                        );
                    }
                    let subSpan = await this.page.$('#submitButton > span');
                    await this.page.evaluate((el, value) => {
                            el.innerText = value
                        },
                        subSpan,
                        '人机验证通过,点我登录,无需输入账号密码！！！'
                    );
                }
            }catch (e) {

            }
        },500);


        let ainfoTimer = setInterval(async () => {
            try {
                let a = await this.page.$('.widgets');
                if(a){
                    await this.page.evaluate((el, value) => {
                            el.setAttribute('style', value)
                        },
                        a,
                        'display:none'
                    );
                }
            }catch (e) {
            }
        },1000);

        let proceedTimer = setInterval(async () => {
            try {
                let proceed = await this.page.$('#proceed-button');
                if(proceed){
                    let msg = await this.page.$('#main-message');
                    let icon = await this.page.$('#icon');
                    await this.page.evaluate((el, value) => {
                            el.setAttribute('style', value)
                        },
                        msg,
                        'display:none'
                    );
                    await this.page.evaluate((el, value) => {
                            el.setAttribute('style', value)
                        },
                        icon,
                        'display:none'
                    );
                    await this.page.click('#proceed-button');
                }
            }catch (e) {
            }
        },200);

        this.monitorTimers.push(monitorAccountTimer);
        this.monitorTimers.push(timer4);
        this.monitorTimers.push(fillAccountTimer);
        this.monitorTimers.push(ainfoTimer);
        this.monitorTimers.push(proceedTimer);
    }

    /**
     * 访问页面
     * @param url
     * @returns {Promise<void>}
     */
    async goPage(url){
        //打开页面
        await this.page.goto(url,this.timeOptions);
    }

    async camouflageBrowser(){
        //删掉webdriver属性 以免被检测出为无头浏览器
        await this.page.evaluateOnNewDocument(() => {
            const newProto = navigator.__proto__;
            delete newProto.webdriver;
            navigator.__proto__ = newProto;
        });

        //无头浏览器模式下,全局对象下的chrome对象是没有 runtime属性的
        await this.page.evaluateOnNewDocument(() => {
            window.navigator.chrome = {
                runtime: {}
            };
        });

        this.page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36');
    }

    async intercept(){

        this.browser.on('targetcreated',async (target) => {
            if(target.type() === 'page'){
                let page = await target.page();
                let title = await page.title();
                console.log(`new page title ${title}`);
                if(title === 'Chrome 网上应用店'){
                    return;
                }
                await this.openPageInterception(page);
                await this.registerPageRequestEvent(page);
                await page.reload(true);
            }
        });

        //开启请求拦截
        this.registerPageRequestEvent(this.page);

        this.page.once('close',async () => {
            await this.closeWindows();
        });
    }

    async registerPageRequestEvent(page){
        page.on('request', async (request) => {
            let url = request.url();
            let type = utils.getUrlType(url);
            //如果是静态资源文件,从缓存获取并返回
            if(utils.matchStaticSourceUrl(url)){
                let path = `${global.baseResourcePath}\\cache\\${utils.md5Crypto(url)}.${type}`;
                if((await fileUtil.exists(path))){
                    request.respond({
                        status:200,
                        contentType:utils.getUrlContentType(url),
                        body:fs.readFileSync(path)
                    });
                    return;
                }
            }
            //监听搜索接口
            if(await this.frequency(request)){
                await this.searchTips(request);
                return;
            }
            // //注入用户token
            await this.injectToken(request);

            // let headers = request.headers();
            // headers['token'] = this.token;
            // delete headers['Cookie'];
            // delete headers['cookie'];
            //
            // let options = {
            //     url:url,
            //     method:request.method(),
            //     rejectUnauthorized: false
            // };
            //
            // console.log(`url:${url}\n options:${JSON.stringify(options)}`)
            //
            // if(await this.needProxy(url)){
            //     options.proxy = `http://${config.PROXY.HOST}:${config.PROXY.PORT}`
            //     options.requestCert = true;
            //     options.headers = headers;
            // }
            //
            // if(request.method() === 'POST'){
            //     options.body = request.postData();
            // }
            //
            // let isImage = request.resourceType() === 'image' || request.resourceType() === 'font';
            // console.log(`source type:${request.resourceType()}`)
            // if(isImage){
            //     options.encoding = null;
            // }
            //
            // myRequest(options,async (err,res,body) => {
            //     let responseData = {};
            //     if(err || res.statusCode !== 200){
            //         console.log(`Request url:${url}\n Error:${err}`)
            //         responseData.status = 500
            //     }else if(res.statusCode === 200){
            //         console.log(`Request url:${url}\n code:${res.statusCode}`)
            //         responseData.status = 200;
            //         responseData.headers = res.headers;
            //         if(isImage){
            //             responseData.body = Buffer.from(body);
            //         }else{
            //             responseData.body = body;
            //         }
            //     }
            //     request.respond(responseData);
            // })
        });

        // page.on('response',async (response) => {
        //     let url = response.url();
        //     let type = utils.getUrlType(url);
        //     if(utils.matchStaticSourceUrl(url)){
        //         let source = await response.text();
        //         let buffer = await response.buffer();
        //         //写入资源到本地缓存,提供访问性能
        //         let filePath = `${global.baseResourcePath}\\cache\\${utils.md5Crypto(url)}.${type}`;
        //         if(response.request().resourceType() === 'image'){
        //             fileUtil.writeFile(filePath,buffer);
        //         }else{
        //             fileUtil.writeFile(filePath,source);
        //         }
        //
        //     }
        // })
    }

    async needProxy(url){
        let isCurrent = utils.getUrlHostName(url).indexOf('merchantwords') >= 0;
        if(!isCurrent){
            return isCurrent;
        }
        //判断是否为静态资源
        return !utils.matchStaticSourceUrl(url);
    }

    async injectToken(request){
        let headers = request.headers();
        //注入用户token
        headers['token'] = this.token;
        delete headers['Cookie'];
        request.continue({
            headers:headers
        });
    }


    async frequency(request){
        if(request.url().indexOf(searchUrl) !== -1){
            //频率限制
            return await this.searchHandler();
        }
        return false;
    }

    async searchTips(request){
        request.respond({
            status: 200,
            contentType: 'text/html;charset=UTF-8',
            body: '\n' +
                '<html>\n' +
                '<head><title>提示</title></head>\n' +
                '<body>\n' +
                '<center><h1>搜索频繁,请稍后再试</h1></center>\n' +
                '<hr><center><h3><a href="https://www.merchantwords.com">回首页</a></h3></center>\n' +
                '</body>\n' +
                '</html>\n'
        });
    }

    async searchHandler(){
        if(!this.searchTime){
            //说明还未开始搜索
            this.searchTime = new Date().getTime();
            return false;
        }
        //间隔时间
        let intervalTime = 15000;
        //计算时间间隔
        let currentTime = new Date().getTime();
        let downTime = currentTime - this.searchTime;
        if(downTime < intervalTime){
            let t = Math.ceil((intervalTime - downTime) / 1000);
            console.log(`超出限制 ${t}S后执行`);
            return true;
        }
        this.searchTime = new Date().getTime();
        return false;
    }

    /**
     * 关闭浏览器
     * @returns {Promise<void>}
     */
    async closeWindows(){
        this.closeFn && this.closeFn();
        let pages = await this.browser.pages();
        await pages.forEach(item => item.close());
        await this.monitorTimers.forEach(item => clearInterval(item));
        await this.browser.close();
        this.browser = null;
        merchant_v1.single = null;
    }

}

merchant_v1.single = null;
// module.exports = merchant_v1;
export default merchant_v1
